package cn.wolfcode.shiro;


import cn.wolfcode.domain.Employee;
import cn.wolfcode.domain.Permission;
import cn.wolfcode.mapper.EmployeeMapper;
import cn.wolfcode.mapper.PermissionMapper;
import cn.wolfcode.mapper.RoleMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义数据源
 */

// 贴注解
@Component("crmRealm")

public class CrmRealm extends AuthorizingRealm{
    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    // 将容器中的配置的凭证匹配器注入给当前的Realm对象
    // 在该Realm中使用指定的凭证匹配器来完成匹配的操作
    @Autowired
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }

    /**
     * 提供授权信息(当前登录用户拥有的权限)
     * @param principals
     * @return
     */

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取当前登录用户的对象
         /* 如果框架的参数没有提供给我们,就可以用工具参数
        Subject subject = SecurityUtils.getSubject();
        Employee employee = (Employee)subject.getPrincipal();*/

         // 框架有提供参数,直接拿来用即可
        Employee employee = (Employee)principals.getPrimaryPrincipal();
        // info对象中数据就是当前用户的权限和角色的信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 判断是否为超级管理员
        if (!employee.isAdmin()){
            // 根据员工id查询员工的角色编码集合
            List<String> roles = roleMapper.selectSnByEmpId(employee.getId());
            info.addRoles(roles);
            // 根据员工id查询员工的权限表达式集合
            List<String> expression = permissionMapper.selectExpressionByEmpId(employee.getId());
            info.addStringPermissions(expression);
        }else {
            info.addStringPermission("*:*"); // 拥有所有权限,使用通配符
            info.addRole("ADMIN");// 管理员角色,可给可不给,给了就方便直接使用subject就可以判断是否为管理员
        }

        return info;
    }

    /**
     * 提供认证信息的数据(登录需要用到)
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 通过令牌token获取到用户名,并将用户名进行加"盐"操作
        String username = token.getPrincipal().toString(); // employee
        // 通过token获取到用户名,当用户点击登录的时候会将用户名/密码封装成token对象传过来.
       /* UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();*/
        // 查询数据库中是否存在该用户名
        Employee employee = employeeMapper.selectByName(username);
        if (employee != null
                ){
            // 如果存在,就把用户的用户名和密码,封装到AuthenticationInfo对象,最后返回给shiro使用
            //  第一个参数员工对象,(方便后续直接用subject对象来获取授权)
            // 第三个参数是当前的数据源名字(用来区分数据是来自哪个数据源)
            //return new SimpleAuthenticationInfo(employee,employee.getPassword(),this.getName());
            return new SimpleAuthenticationInfo(employee, //身份信息
                    employee.getPassword(), // 凭证
                    ByteSource.Util.bytes(employee.getName()), // 盐
                    this.getName()); // Realm 名称
        }
        // 用户名不存在,返回null (我们不用做try catch操作,由shioro底层实现)
        return null;
    }
}
